package com.quanyue.mechanics.user.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.quanyue.auto.cache.core.CacheService;
import com.quanyue.auto.util.AssertUtils;
import com.quanyue.auto.util.Md5Encoder;
import com.quanyue.auto.util.StringUtils;
import com.quanyue.mechanics.domain.constant.CacheConstants;
import com.quanyue.mechanics.domain.entity.Manager;
import com.quanyue.mechanics.user.mapper.ManagerMapper;
import com.quanyue.mechanics.user.service.ManagerService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ManagerServiceImpl implements ManagerService {

    @Autowired
    private ManagerMapper managerMapper;
    @Autowired
    private CacheService cacheService;

    @Override
    public List <Manager> findById(Integer id) {
        List <Manager> list = new ArrayList <>();
        Map <Integer, Manager> map = managerMap();
        Manager manager = map.get(id);
        list.add(manager);
        return list;
    }

    @Override
    public Manager sessionManager(Integer id) {
        Manager manager = managerMap().get(id);
        Manager sessionManager = new Manager();
        BeanUtils.copyProperties(manager, sessionManager);
        return sessionManager;
    }

    @Override
    public List <Manager> findAll(Integer id) {
        List <Manager> managerList = new ArrayList <>();
        Manager manager = managerMapper.findOne(id);
        managerList.add(manager);
        if (managerList.isEmpty()) return Collections.EMPTY_LIST;
        return managerList;
    }

    @Override
    public Manager findByPassword(String username, String password) {
        // 判断是否超出登录次数限制
        Type type = new TypeReference<Map <String, Integer>>() {
        }.getType();
        // 验证用户名密码
        Manager manager = managerNameMap().get(username);
        if (manager != null && manager.getPassword().equals(password)) {
            return manager;
        }
        return null;
    }

    @Override
    public Manager add(Manager manager) {
        manager.setCreateTime(LocalDateTime.now());
        manager.setModifyTime(manager.getCreateTime());
        // just temporary
        manager.setPassword(Md5Encoder.md5(manager.getPassword()));
        manager.setDelFlag(false);
        managerMapper.insert(manager);
        this.updateCache(manager);
        return manager;
    }

    @Override
    public void update(Manager manager) {
        Manager checkManager = managerMapper.findOne(manager.getId());
        AssertUtils.notNull(checkManager, "没有该管理员");
        manager.setCreateTime(checkManager.getCreateTime());
        manager.setDelFlag(false);
        manager.setModifyTime(LocalDateTime.now());
        if (StringUtils.isNotBlank(manager.getPassword()))
            manager.setPassword(Md5Encoder.md5(manager.getPassword()));
        managerMapper.updateSelective(manager);
        this.updateCache(manager);
    }

    @Override
    public void updatePassword(Integer id, String current, String newPassword) {
        Manager manager = managerMap().get(id);
        AssertUtils.isTrue(manager.getPassword().equals(Md5Encoder.md5(current)), "旧密码不正确");
        Manager update = new Manager();
        update.setPassword(Md5Encoder.md5(newPassword));
        update.setId(manager.getId());
        managerMapper.updateSelective(update);
        manager.setPassword(newPassword);
    }

    @Override
    public void remove(Integer id) {
        Manager manager = new Manager();
        manager.setDelFlag(true);
        manager.setId(id);
        managerMapper.updateSelective(manager);
        manager = managerMap().get(id);
        managerNameMap().remove(manager.getUserName());
        managerMap().remove(id);
    }


    private void updateCache(Manager manager) {
        managerMap().put(manager.getId(), manager);
        managerNameMap().put(manager.getUserName(), manager);
    }

    private Map <Integer, Manager> managerMap() {
        Type type = new TypeReference<Map <Integer, Manager>>() {
        }.getType();
        return cacheService.get(CacheConstants.MANAGER_ID.name(), type);
    }

    private Map <String, Manager> managerNameMap() {
        Type type = new TypeReference<Map <String, Manager>>() {
        }.getType();
        return cacheService.get(CacheConstants.MANAGER_NAME.name(), type);
    }

    @PostConstruct
    private void init() {
        cacheService.set(CacheConstants.MANAGER_ID.name(), managerMapper.findAllValid()
                .stream()
                .collect(Collectors.toMap(Manager::getId, m -> m)));
        cacheService.set(CacheConstants.MANAGER_NAME.name(), managerMapper.findAllValid()
                .stream()
                .collect(Collectors.toMap(Manager::getUserName, m -> m)));
    }
}
